package com.cr.backbone.util;


/**
 * 
 * Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一，大家可以查看RFC2045～RFC2049，上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如，在Java
 * Persistence系统Hibernate中，就采用了Base64来将一个较长的唯一标识符（一般为128-bit的UUID）编码为一个字符串，用作HTTP表单和HTTP
 * GET
 * URL中的参数。在其他应用程序中，也常常需要把二进制数据编码为适合放在URL（包括隐藏表单域）中的形式。此时，采用Base64编码不仅比较简短，同时也具有不可读性，即所编码的数据不会被人用肉眼所直接看到。
 * 
 * @author huxh
 * 
 */
public class UtilsBase64 {

	private static UtilsBase64 instance = new UtilsBase64();

	public static synchronized UtilsBase64 getInstance() {
		if (instance == null) {
			instance = new UtilsBase64();
		}
		return instance;
	}

	/**
	 * 将原始数据编码为base64编码
	 */
	public String encode(String str) {

		if (str == null || "".equals(str.trim())) {
			return "";
		}
		byte[] data = str.getBytes();
		char[] out = new char[((data.length + 2) / 3) * 4];

		for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
			boolean quad = false;
			boolean trip = false;
			int val = (0xFF & (int) data[i]);
			val <<= 8;
			if ((i + 1) < data.length) {
				val |= (0xFF & (int) data[i + 1]);
				trip = true;
			}
			val <<= 8;
			if ((i + 2) < data.length) {
				val |= (0xFF & (int) data[i + 2]);
				quad = true;
			}
			out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 1] = alphabet[val & 0x3F];
			val >>= 6;
			out[index + 0] = alphabet[val & 0x3F];
		}
		return new String(out);
	}

	/**
	 * 将base64编码的数据解码成原始数据
	 */
	public String decode(String str) {
		if (str == null || "".equals(str.trim())) {
			return "";
		}
		char[] data = str.toCharArray();
		int len = ((data.length + 3) / 4) * 3;
		if (data.length > 0 && data[data.length - 1] == '=') {
			--len;
		}
		if (data.length > 1 && data[data.length - 2] == '=') {
			--len;
		}
		byte[] out = new byte[len];
		int shift = 0;
		int accum = 0;
		int index = 0;
		for (int ix = 0; ix < data.length; ix++) {
			int value = codes[data[ix] & 0xFF];
			if (value >= 0) {
				accum <<= 6;
				shift += 6;
				accum |= value;
				if (shift >= 8) {
					shift -= 8;
					out[index++] = (byte) ((accum >> shift) & 0xff);
				}
			}
		}
		if (index != out.length) {
			return null;
			// throw new Error("miscalculated data length!");
		}
		return new String(out);
	}

	static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
			.toCharArray();

	static private byte[] codes = new byte[256];
	static {
		for (int i = 0; i < 256; i++) {
			codes[i] = -1;
		}
		for (int i = 'A'; i <= 'Z'; i++) {
			codes[i] = (byte) (i - 'A');
		}
		for (int i = 'a'; i <= 'z'; i++) {
			codes[i] = (byte) (26 + i - 'a');
		}
		for (int i = '0'; i <= '9'; i++) {
			codes[i] = (byte) (52 + i - '0');
		}
		codes['+'] = 62;
		codes['/'] = 63;
	}

	public static void main(String[] args) throws Exception {

		// String ss= instance.decode("NQ==");
		// System.out.println(ss);
		String a = "将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码将 s 进行 BASE64 编码,针对url的编码userId=1441&mailId=981&date=2011-02-15-62";
		String b = encodeForUrl(a.getBytes());// 编码金融超市执行。
		// b = b.replace("\n", "");
		// b = b.replace("\r", "");
		System.out.println(b);

		System.out.println(new String(decodeForUrl(b)));// 理财教育网执行解码
		
		//2012-05-15 测试Base64 加密、解密工具类：
		//Base64.encode();		BASE64 编码 
		//Base64.decodeForUrl();BASE64 解码
		String bbb = encodeForUrl("金融理财的概念".getBytes());//模拟，金融超市编码
		System.out.println(bbb);		
		System.out.println(new String(UtilsBase64.decodeForUrl(bbb)));//模拟，理财网解码
		
		new String(UtilsBase64.decodeForUrl(bbb));
		
		
		

	}

	/**
	 * 将 s 进行 BASE64 编码
	 * 
	 * @param s
	 * @return
	 */
	public static String encode(byte[] s) {
		if (s == null)
			return null;
		return (new sun.misc.BASE64Encoder()).encode(s);
	}

	/**
	 * 将 s 进行 BASE64 编码,针对url的编码
	 * 
	 * @param s
	 * @return
	 */
	public static String encodeForUrl(byte[] s) {
		if (s == null)
			return null;
		String standerBase64 = encode(s);
		String encodeForUrl = standerBase64;
		// 转成针对url的base64编码
		encodeForUrl = encodeForUrl.replace("=", "");
		encodeForUrl = encodeForUrl.replace("+", "*");
		encodeForUrl = encodeForUrl.replace("/", "-");
		// 去除换行
		encodeForUrl = encodeForUrl.replace("\n", "");
		encodeForUrl = encodeForUrl.replace("\r", "");

		// 转换*号为 -x-
		// 防止有违反协议的字符
		encodeForUrl = encodeSpecialLetter1(encodeForUrl);

		return encodeForUrl;

	}

	/**
	 * 转换*号为 -x-， 为了防止有违反协议的字符，-x 转换为-xx
	 * 
	 * @param str
	 * @return
	 */
	private static String encodeSpecialLetter1(String str) {
		str = str.replace("-x", "-xx");
		str = str.replace("*", "-x-");
		return str;
	}

	/**
	 * 转换 -x-号为*，-xx转换为-x
	 * 
	 * @param str
	 * @return
	 */
	private static String decodeSpecialLetter1(String str) {
		str = str.replace("-x-", "*");
		str = str.replace("-xx", "-x");
		return str;
	}

	/**
	 * 将 BASE64 编码的字符串 s 进行解码
	 * 
	 * @param s
	 * @return
	 */
	public static byte[] decodeForUrl(String s) {
		if (s == null)
			return null;
		s = decodeSpecialLetter1(s);
		s = s.replace("*", "+");
		s = s.replace("-", "/");
		s += "=";
		sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
		try {
			byte[] b = decoder.decodeBuffer(s);
			return b;
		} catch (Exception e) {
			return null;
		}
	}

}
